package com.mx.base.language.script

import org.apache.poi.ss.usermodel.*
import java.io.File
import java.io.FileOutputStream

/**
 * @author: xiao.ma
 * Date: 2022/1/28 14:03
 * Desc:
 */

object ExportScript {

    /**
     * 获取resPath 下的所有strings.xml文件
     */
    fun getAllLanguageFile(resPath: String): Array<File> {
        return File(resPath).listFiles { file ->
            file.isDirectory && file.name.startsWith("values")
        } ?: arrayOf()
    }

    fun getTargetLanguageFile(resPath: String, targets: MutableList<String>): Array<File> {
        return File(resPath).listFiles { file ->
            file.isDirectory && targets.any { target -> target == file.name }
        } ?: arrayOf()
    }

    /**
     *获取resPath targets的翻译
     * 以各语言values文件夹名称为key value 为以string name 为key，value为对应翻译的map
     * MutableMap<values-xxx, MutableMap<name, translate>>
     */
    fun getLanguageMap(resPath: String, targets: MutableList<String>): MutableMap<String, MutableMap<String, String>> {
        println("---->getLanguageMap=$targets")
        val languageMap = mutableMapOf<String, MutableMap<String, String>>()
        val targetFiles = if (targets.isEmpty()) getAllLanguageFile(resPath) else
            getTargetLanguageFile(resPath, targets)
        targetFiles.forEach {
            languageMap[it.name] = XmlHelper.readStringXml("${it.absoluteFile}/strings.xml")
        }
        return languageMap
    }

    /**
     * 按各module,填充数据到excel
     */
    private fun fillDataToExcelByModule(
        workbook: Workbook,
        baseLanguage: String,
        exports: MutableList<String>,
        module: File,
        resPath: String
    ) {
        println("---->fillDataToExcel=${module.name}")
        val sheet = workbook.createSheet(module.name)
        exports.add(baseLanguage)
        val languageMap = getLanguageMap("${module.absoluteFile}/$resPath", exports)
        val baseXmlMap = languageMap[baseLanguage]
        languageMap.remove(baseLanguage)
        var rowNum = 0
        val header = sheet.createRow(rowNum++)
        val header2 = sheet.createRow(rowNum++)
        var columnNum = 0

        //填充头部数据
        header.createCell(columnNum).apply {
            setCellValue(baseLanguage)
        }
        header2.createCell(columnNum++).apply {
            setCellValue(Constants.languageKeyMap[baseLanguage] ?: "")
        }
        //填充头部数据
        languageMap.forEach {
            header.createCell(columnNum).apply {
                setCellValue(it.key)
            }
            header2.createCell(columnNum++).apply {
                setCellValue(Constants.languageKeyMap[it.key] ?: "")
            }
        }

        baseXmlMap?.forEach { baseMap ->
            columnNum = 0
            val row = sheet.createRow(rowNum++)
            row.createCell(columnNum++).apply {
                setCellValue(baseMap.value)
            }
            languageMap.forEach { lMap ->
                row.createCell(columnNum++).apply {
                    setCellValue(lMap.value[baseMap.key])
                }
            }
        }

    }

    private fun genExcelByLanguage(
        excelDir: String,
        baseLanguage: String,
        module: File,
        resPath: String
    ) {
        val baseXmlMap =
            XmlHelper.readStringXml("${module.absoluteFile}/$resPath/$baseLanguage/strings.xml")
        getAllLanguageFile("${module.absoluteFile}/$resPath").forEach { languageFile ->
            if (languageFile.name != baseLanguage) {
                val workbook = WorkbookFactory.create(true)
                val sheet = workbook.createSheet("sheet")
                sheet.setColumnWidth(0, 25600)
                sheet.setColumnWidth(1, 25600)
                val languageMap = XmlHelper.readStringXml(File(languageFile, "strings.xml"))
                var rowNum = 0
                val header = sheet.createRow(rowNum++)
                val header2 = sheet.createRow(rowNum++)
                header.createCell(0).apply {
                    setCellValue(baseLanguage)
                }
                header.createCell(1).apply {
                    setCellValue(languageFile.name)
                }
                header2.createCell(0).apply {
                    setCellValue(Constants.languageKeyMap[baseLanguage] ?: "")
                }

                header2.createCell(1).apply {
                    setCellValue(Constants.languageKeyMap[languageFile.name] ?: "")
                }

                baseXmlMap.forEach { baseMap ->
                    val row = sheet.createRow(rowNum++)
                    row.createCell(0).apply {
                        setCellValue(baseMap.value)
                    }
                    row.createCell(1).apply {
                        setCellValue(languageMap[baseMap.key])
                    }
                }
                val excelFile = File("$excelDir/${languageFile.name}.xlsx").apply {
                    if (exists()) {
                        delete()
                    }
                }
                FileOutputStream(excelFile).use { fos ->
                    workbook.write(fos)
                }
            }
        }

    }

    fun genExcel(
        excelDir: String,
        excelName: String,
        baseLanguage: String,
        exports: MutableList<String>,
        modules: Array<File>,
        resPath: String,
        merge: Boolean
    ) {
        println("---->genExcel start")
        if (merge) {
            val workbook = WorkbookFactory.create(true)
            modules.forEach { module ->
                fillDataToExcelByModule(workbook, baseLanguage, exports, module, resPath)
            }
            val excelFile = File("$excelDir/$excelName").apply {
                if (exists()) {
                    delete()
                }
            }
            FileOutputStream(excelFile).use { fos ->
                workbook.write(fos)
            }
        } else {
            modules.forEach { module ->
                val workbook = WorkbookFactory.create(true)
                fillDataToExcelByModule(workbook, baseLanguage, exports, module, resPath)
                val excelFile = File("$excelDir/${module.name}_$excelName").apply {
                    if (exists()) {
                        delete()
                    }
                }
                FileOutputStream(excelFile).use { fos ->
                    workbook.write(fos)
                }
            }
        }
        println("---->genExcel end")
    }

    fun byLanguageCategoryGenExcel(
        excelDir: String,
        baseLanguage: String,
        modules: Array<File>,
        resPath: String
    ) {
        modules.forEach { module ->
            if (checkAndMkdir("$excelDir/${module.name}")) {
                genExcelByLanguage("$excelDir/${module.name}", baseLanguage, module, resPath)
            }
        }
    }

    private fun checkAndMkdir(dirPath: String): Boolean {
        val file = File(dirPath).apply {
            if (!exists()) {
                mkdirs()
            }
        }
        return file.exists()
    }

    class Build {
        /**
         * android project 路径
         */
        private var projectPath = ""

        /**
         * 基础语言
         */
        private var baseLanguage = "values-zh-rCN"

        /**
         *导出的文件夹路径
         */
        private var exportDirPath = ""

        /**
         *excel name
         *在byLanguageCategory=false下有效
         */
        private var excelName = "strings.xlsx"

        /**
         *android project 的翻译所在相对路径
         */
        private var resPath = "src/main/res"

        /**
         * 在byLanguageCategory=false下有效
         *为true 各个module 的翻译汇总在一个excel
         * 为false 按module分开为各excel
         * @see builder
         */
        private var merge: Boolean = false

        /**
         * 为true  module下baseLanguage的所有翻译按各语言生成独立的excel文档
         * 为false module下baseLanguage的所有翻译汇总在一个excel
         * @see byLanguageCategoryGenExcel
         */
        private var byLanguageCategory = false

        private var exportLanguages = mutableListOf<String>()

        fun setProjectPath(projectPath: String): Build {
            this.projectPath = projectPath
            return this
        }

        fun setBaseLanguage(baseLanguage: String): Build {
            this.baseLanguage = baseLanguage
            return this
        }

        fun setExportDirPath(exportDirPath: String): Build {
            this.exportDirPath = exportDirPath

            return this
        }

        fun setExcelName(excelName: String): Build {
            this.excelName = excelName.plus(".xlsx")
            return this
        }

        fun byLanguageCategory(boolean: Boolean): Build {
            this.byLanguageCategory = boolean
            return this
        }

        fun setMerge(merge: Boolean): Build {
            this.merge = merge
            return this
        }

        fun setExportLanguages(exportLanguages: MutableList<String>): Build {
            this.exportLanguages = exportLanguages
            return this
        }

        private fun fileFilter(file: File): Boolean {
            return file.isDirectory
                    && !file.name.startsWith(".")
                    && File(
                    file.absolutePath,
                    "$resPath/$baseLanguage/strings.xml"
            ).run {
                exists() && isFile
            }
        }

        fun builder() {
            if (exportDirPath.isBlank()) {
                exportDirPath = projectPath
            }
            val modules = File(projectPath).listFiles { file -> fileFilter(file) } ?: arrayOf()
            if (byLanguageCategory) {
                byLanguageCategoryGenExcel(exportDirPath, baseLanguage, modules, resPath)
            } else {
                genExcel(exportDirPath, excelName, baseLanguage, exportLanguages, modules, resPath, merge)
            }
        }
    }
}

fun main() {
    ExportScript.Build()
        .setProjectPath("C:\\Android\\wk\\peanut_gbg_peanut_v9.12.10.1x")
        .setBaseLanguage("values-zh-rCN")
        .setExportDirPath("D:\\OutLanguage")
        .byLanguageCategory(true)
        .setExportLanguages(mutableListOf("values-ro-rRO"))
        .setMerge(false)
        .builder()
}